package com.py.credit.service.impl;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.alibaba.fastjson.JSONArray;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.py.credit.common.ServiceException;
import com.py.credit.common.logs.AccessLogger;
import com.py.credit.dao.BatchFileDao;
import com.py.credit.dao.BatchLogDao;
import com.py.credit.dao.ColumnDao;
import com.py.credit.dao.DataEntryDao;
import com.py.credit.entity.BatchLog;
import com.py.credit.entity.Column;
import com.py.credit.entity.DynamicSqlEntity;
import com.py.credit.entity.SysUser;
import com.py.credit.entity.Table;
import com.py.credit.entity.TableResult;
import com.py.credit.entity.common.LogEnum;
import com.py.credit.service.ContentService;
import com.py.credit.service.DataEntryService;
import com.py.credit.service.ManualService;
import com.py.credit.service.StepLogService;
import com.py.credit.service.TableService;
import com.py.credit.service.WriteLogsService;
import com.py.credit.service.excel.read.service.InspectDataStyleService;
import com.py.credit.utils.UuidUtil;

@Service
public class ManualServiceImpl implements ManualService {

    private static final Logger LOG = LoggerFactory.getLogger(ManualServiceImpl.class);

    private static final String CHECKREPEAT_NO = "N";
    
	private static final int NUM_1000 = 1000;

	private static final int NUM_1 = 1;

	private static final int NUM_2 = 2;
	
	
    @Autowired
    BatchLogDao batchLogDao;

    @Autowired
    ContentService contentService;

    @Autowired
    BatchFileDao batchFileDao;

	@Autowired
	private DataEntryDao dataEntryDao;
	
    @Autowired
    ColumnDao columnDao;

    @Autowired
    WriteLogsService writeLogsService;

    @Autowired
    private TableService tableService;

    @Autowired
    @Qualifier("default")
    private InspectDataStyleService inspectDataStyleService;

    @Autowired
    private DataEntryService dataEntryService;

    @Autowired
    private StepLogService stepLogService;

	
    @Override
    @Transactional
    public Map<String, Object> manualCollection(String data, Integer tableId, Integer rootId, SysUser userInfo, Integer contentId,String absolutepath) throws FileNotFoundException, IOException {
        StringBuilder error = new StringBuilder();
		Map<String, Object> resultMap = new HashMap<>();
        int totalCount = 0;
		int totalDuplicationCount = 0;  
     	String errorMess = null;    	
     	int errorCount = 0;
     	Map<String, Object> checkResultMap = null;
        // 获取数据表信息
        Table table = tableService.queryCubeById(tableId);
        table.setRootId(rootId);
        Long topDeptId = userInfo.getOfficeId();
        String pIds = userInfo.getAllParentId();
        if (StringUtils.isNotBlank(pIds)) {
            String t = StringUtils.split(pIds, ",")[0];
            topDeptId = StringUtils.isNoneBlank(t) ? Long.valueOf(t) : topDeptId;
        }
        String tipId = tableId + "_" + topDeptId;
        TableResult table1 = contentService.getTableColumns(tableId, contentId, tipId);
        List<Column> columns = table1.getColumns();
        String batchId = UuidUtil.getInstance().getUUid();
        // 新增批次信息
        batchLogDao.addBatchLog(batchId.toString(), tableId, "2", rootId, userInfo.getOfficeId(), userInfo.getId(),
                LogEnum.CLZ, null);
        // 获取批次详细信息
        BatchLog batchLog = batchLogDao.select(batchId);
        List<Map<String, Object>> listDataMap = JSONObject.parseObject(data.replaceAll(" ", ""),
                new TypeReference<List<Map<String, Object>>>() {
                });
		List<Map<String, Object>> listDataMap2 = (List<Map<String, Object>>) JSONArray.parse(JSONArray.toJSONString(listDataMap));
        for(Map<String, Object> map : listDataMap) {
        	if(table.getTableId()==210001){				
	        	String A000001 = CleanData(map.get("A000001").toString()).replaceAll("\\(", "（").replaceAll("\\)", "）");
				map.put("A000001", A000001);
	        	String CF_WSH = CleanData(map.get("CF_WSH").toString()).replaceAll("\\[", "〔").replaceAll("\\]", "〕").
	        			replaceAll("【", "〔").replaceAll("】", "〕").
	        			replaceAll("﹝", "〔").replaceAll("﹞", "〕").
	        			replaceAll("［", "〔").replaceAll("］", "〕").
	        			replaceAll("\\{", "〔").replaceAll("\\}", "〕");
				map.put("CF_WSH", CF_WSH);	        	
			}else if(table.getTableId()==210003){		
				String B000001 = CleanData(map.get("B000001").toString()).replaceAll("\\(", "（").replaceAll("\\)", "）");
				map.put("B000001", B000001);
	        	String CF_WSH = CleanData(map.get("CF_WSH").toString()).replaceAll("\\[", "〔").replaceAll("\\]", "〕").
	        			replaceAll("【", "〔").replaceAll("】", "〕").
	        			replaceAll("﹝", "〔").replaceAll("﹞", "〕").
	        			replaceAll("［", "〔").replaceAll("］", "〕").
	        			replaceAll("\\{", "〔").replaceAll("\\}", "〕");
				map.put("CF_WSH", CF_WSH);	        	
			}else if(table.getTableId()==210002) {		
				String B000001 = CleanData(map.get("B000001").toString()).replaceAll("\\(", "（").replaceAll("\\)", "）");
				map.put("B000001", B000001);
				String XK_WSH = CleanData(map.get("XK_WSH").toString()).replaceAll("\\[", "〔").replaceAll("\\]", "〕").
	        			replaceAll("【", "〔").replaceAll("】", "〕").
	        			replaceAll("﹝", "〔").replaceAll("﹞", "〕").
	        			replaceAll("［", "〔").replaceAll("］", "〕").
	        			replaceAll("\\{", "〔").replaceAll("\\}", "〕");
				map.put("XK_WSH", XK_WSH);				
			}else if(table.getTableId()==210000) {				
				String A000001 = CleanData(map.get("A000001").toString()).replaceAll("\\(", "（").replaceAll("\\)", "）");
				map.put("A000001", A000001);
				String XK_WSH = CleanData(map.get("XK_WSH").toString()).replaceAll("\\[", "〔").replaceAll("\\]", "〕").
	        			replaceAll("【", "〔").replaceAll("】", "〕").
	        			replaceAll("﹝", "〔").replaceAll("﹞", "〕").
	        			replaceAll("［", "〔").replaceAll("］", "〕").
	        			replaceAll("\\{", "〔").replaceAll("\\}", "〕");
				map.put("XK_WSH", XK_WSH);			
			}
        }       
        int size = listDataMap.size();
        // 处理流程日志
        stepLogService.addStepLog(batchId, "解析手工采集到的" + size + "条数据。");
        // 重复性校验
        stepLogService.addStepLog(batchId, "开始重复性校验：0到" + size + "行数据。");
        // 数据是否需要重复性校验
        boolean checkRepeat = true;   
    	long duplicationStartTimeMill = System.currentTimeMillis();
        // 数据重复性校验
        Map<String, Object> duplicationCheck = inspectDataStyleService.duplicationCheck(listDataMap, table, columns,
                false, checkRepeat);
        long duplicationEndTimeMill = System.currentTimeMillis();
		AccessLogger.info("数据采集重复性校验耗时", "", "",
				"数据采集重复性校验耗时" + (duplicationEndTimeMill - duplicationStartTimeMill) + "ms");
        String duplicationMess = String.valueOf(duplicationCheck.get("duplicationMess"));
    	int duplicationCount = (int) duplicationCheck.get("duplicationCount");
		if (duplicationCount != 0) {
			totalDuplicationCount += duplicationCount;
			writeLogsService.writeLogFile(batchLog.getId(), duplicationMess, absolutepath);
		}
        stepLogService.addStepLog(batchId, "开始校验手工采集的0到" + size + "行数据");
       
    	// 数据库规则校验
		long dbStartTimeMill = System.currentTimeMillis();


		Map<String, Object> dbCheck = inspectDataStyleService.dataFormatCheck(batchLog, listDataMap, table,
				columns,listDataMap2);
		long dbEndTimeMill = System.currentTimeMillis();
		AccessLogger.info("数据采集数据库规则校验耗时", "", "", "数据采集数据库规则校验耗时" + (dbEndTimeMill - dbStartTimeMill) + "ms");
		if (!CollectionUtils.isEmpty(dbCheck)) {
			int dbCount = Integer.parseInt(String.valueOf(dbCheck.get("count")));
			String dbErr = String.valueOf(dbCheck.get("errMsg"));
			if (dbCount > 0) {
				errorCount += dbCount;
				// 写错误日志
				writeLogsService.writeLogFile(batchLog.getId(), dbErr, absolutepath);
			}
		}
		stepLogService.addStepLog(batchLog.getId(), "开始校验数据");
		// 规则校验
		long styleStartTimeMill = System.currentTimeMillis();
		checkResultMap = inspectDataStyleService.styleCheck(batchLog, listDataMap, table, columns,listDataMap2);
		long styleEndTimeMill = System.currentTimeMillis();
		AccessLogger.info("数据采集表和字段规则校验耗时", "", "",
				"数据采集表和字段规则校验耗时" + (styleEndTimeMill - styleStartTimeMill) + "ms");

		// 获取错误信息
		errorMess = (String) checkResultMap.get("mess");
		Object errlist =  checkResultMap.get("errlist");
		int eachErrorCount = (int) checkResultMap.get("errorCount");
		if (eachErrorCount != 0) {
			errorCount += eachErrorCount;
			// 写错误日志
			writeLogsService.writeLogFile(batchLog.getId(), errorMess, absolutepath);
		}
		long dataStartTimeMill = System.currentTimeMillis();
			// 不使用内存表模式，数据直接入库
			stepLogService.addStepLog(batchLog.getId(), "开始将数据录入至清洗库。");
			addSuccessData(listDataMap, table, batchLog, columns);
			stepLogService.addStepLog(batchLog.getId(), "结束将数据录入至清洗库。");		
	        // 未异常更新本次数据数量	           
	   
	        batchLogDao.modifyBatchLog(batchId, LogEnum.EX_RESULT_S, size, size - errorCount - duplicationCount,
	                   errorCount, duplicationCount, 0, LogEnum.YWC);
	       
		long dataEndTimeMill = System.currentTimeMillis();
		AccessLogger.info("数据采集数据入库耗时", "", "", "数据采集数据入库耗时" + (dataEndTimeMill - dataStartTimeMill) + "ms");
		totalCount += size;
		// 数据总量
		resultMap.put("totalCount", totalCount);
		// 重复数量
		resultMap.put("totalDuplicationCount", totalDuplicationCount);			
		// 未通过校验数量
		resultMap.put("errorCount", errorCount);
		resultMap.put("batchId", batchId);
		resultMap.put("errData", errlist);
		return resultMap;

    }
    
    public static String CleanData(String data) {
		String repl = "";
		if(StringUtils.isNotBlank(data)) {
			Pattern p = Pattern.compile("\\s*|\t|\r|\n");
            Matcher m = p.matcher(data);
            repl = m.replaceAll("").replaceAll("[?]", "").replaceAll("\\?", "");
            Matcher matcher = Pattern.compile("[a-z]").matcher(repl);
            while(matcher.find()){
            	repl = repl.replace(matcher.group(), matcher.group().toUpperCase());
            }
          
		}
		return repl;
		
	}
    
    public void addSuccessData(List<Map<String, Object>> listDataMap, Table table, BatchLog batchLog,
			List<Column> columns) {
		// 根据关联规则查询唯一标识符(根据表的id查询库的code,根据code选用那个库的匹配规则)
		StringBuilder sql = new StringBuilder(200);
		sql.append(" insert into  ");
		sql.append("t_" + table.getResourceId());
		sql.append(" ( ");
		sql.append("tybm, ");
		for (int i = 0; i < columns.size(); i++) {
			sql.append(columns.get(i).getMetricCode());
			sql.append(" , ");
		}
		
		sql.append("status,");
		sql.append("md5,");
		sql.append("batch_id,");
		sql.append("taskId");
		sql.append(" ) ");
		sql.append(" VALUES  ");
		String headSql = sql.toString();
		if (!CollectionUtils.isEmpty(listDataMap)) {
			// 分批次批量插入
			if (listDataMap.size() > NUM_1000) {
				int num = listDataMap.size() / NUM_1000;
				int restNum = listDataMap.size() % NUM_1000;
				for (int i = 0; i < num; i++) {
					List<Map<String, Object>> part = listDataMap.subList(0 + i * NUM_1000, 999 + i * NUM_1000);
					// 添加正确数据
					insertData(part, batchLog, columns, headSql,"t_" + table.getResourceId());
				}
				if (restNum > 0) {
					List<Map<String, Object>> rest = listDataMap.subList(num * NUM_1000, listDataMap.size());
					// 添加正确数据
					insertData(rest, batchLog, columns, headSql,"t_" + table.getResourceId());
				}
			} else {
				// 添加正确数据
				insertData(listDataMap, batchLog, columns, headSql,"t_" + table.getResourceId());
			}
		}
	}
	
	private void insertData(List<Map<String, Object>> listDataMap, BatchLog batchLog, List<Column> columns,
			String headSql,String tablename) {
		List<String> datas = new ArrayList<>(listDataMap.size());
		for (Map<String, Object> dataMap : listDataMap) {
			if(dataMap.containsKey("taskId")) {
				dataEntryDao.deleteErrData(dataMap.get("taskId").toString(),tablename);
			}
			StringBuilder dataSql = new StringBuilder(500);
			buildSql(dataSql, "S", " ", batchLog.getId(), columns, dataMap);
			datas.add(dataSql.toString());
		}
		if (!CollectionUtils.isEmpty(datas)) {
			// 添加正确数据
			DynamicSqlEntity entity = new DynamicSqlEntity(headSql + StringUtils.join(datas, ","));
			
			dataEntryDao.addData(entity);
		}
	}

	private void buildSql(StringBuilder sql, String status, String tybm, String batchLogId, List<Column> columns,
			Map<String, Object> next) {
		sql.append(" ( ");
		sql.append("\'").append(tybm).append("\'").append(", ");
		for (Column column : columns) {
			String value = "";
			if (null != next.get(column.getMetricCode())) {
				
				if(column.getMetricCode().contains("WSH")) {
					value = String.valueOf(next.get(column.getMetricCode())).replaceAll("\\[", "〔").replaceAll("\\]", "〕").
		        			replaceAll("【", "〔").replaceAll("】", "〕").
		        			replaceAll("﹝", "〔").replaceAll("﹞", "〕").
		        			replaceAll("［", "〔").replaceAll("］", "〕").
		        			replaceAll("\\{", "〔").replaceAll("\\}", "〕");	
				}else {
					value = String.valueOf(next.get(column.getMetricCode())).replace("\'", "");
				}
				
			} else {
				value = null;
			}
			if ("number".equals(column.getFieldType())) {
				sql.append(StringUtils.isEmpty(value) ? null : value).append(" , ");
			} else if ("timestamp".equals(column.getFieldType())) {
				sql.append(StringUtils.isEmpty(value) ? null : "\'" + value + "\'").append(" , ");
			} else {
				sql.append(StringUtils.isEmpty(value) ? null : "\'" + value + "\'").append(" , ");
			}
		}
		sql.append("\'").append(status).append("\'").append(", ");
		sql.append("\'").append(String.valueOf(next.get("MD5"))).append("\'").append(", ");
		sql.append("\'").append(batchLogId).append("\'").append(", ");
		sql.append("\'").append(String.valueOf(next.get("taskId"))).append("\'");
		sql.append(" )");
	}

	
}
